package com.hsy.boot.service.util;

import com.hsy.boot.service.annotation.CriteriaLike;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import tk.mybatis.mapper.entity.Example.Criteria;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 条件创建工具类
 *
 * @author huoshengyu
 * @version 1.0
 * @date 2020/3/12 11:33
 */
public class BeanUtil {
    private static final Set<String> IGNORE_PROPERTIES = new HashSet<>();

    static {
        IGNORE_PROPERTIES.add("class");
        IGNORE_PROPERTIES.add("pageNum");
        IGNORE_PROPERTIES.add("pageSize");
    }

    /**
     * 检查对象
     *
     * @param bean 对象
     * @return String
     * @throws Exception 异常
     */
    public static String checkData(Object bean) throws Exception {
        StringBuilder errorMsg = new StringBuilder();
        List<Field> fieldsList = FieldUtils.getAllFieldsList(bean.getClass());
        for (Field field : fieldsList) {
            if (field.isAnnotationPresent(NotNull.class)) {
                String fieldName = field.getName();
                Object value = MethodUtils.invokeExactMethod(bean, methodName(fieldName, false));
                if (Objects.isNull(value) || StringUtils.isBlank(Objects.toString(value))) {
                    errorMsg.append(field.getAnnotation(NotNull.class).message()).append(",");
                }
            }
        }
        if (errorMsg.length() > 0) {
            return errorMsg.substring(0, errorMsg.length() - 1);
        } else {
            return null;
        }
    }

    /**
     * 填充属性条件
     *
     * @param criteria Criteria对象
     * @param bean     参数对象
     * @throws Exception 异常
     */
    public static void fillCriteria(Criteria criteria, Object bean) throws Exception {
        for (Field field : FieldUtils.getAllFieldsList(bean.getClass())) {
            String fieldName = field.getName();
            if (IGNORE_PROPERTIES.contains(fieldName)) {
                continue;
            }
            Object value = MethodUtils.invokeExactMethod(bean, methodName(fieldName, false));
            if (Objects.nonNull(value) && StringUtils.isNotBlank(Objects.toString(value))) {
                if (StringUtils.equals("startCreateTime", fieldName)) {
                    criteria.andGreaterThanOrEqualTo("createTime", value);
                } else if (StringUtils.equals("endCreateTime", fieldName)) {
                    criteria.andLessThanOrEqualTo("createTime", value);
                } else if (StringUtils.equals("startUpdateTime", fieldName)) {
                    criteria.andGreaterThanOrEqualTo("updateTime", value);
                } else if (StringUtils.equals("endUpdateTime", fieldName)) {
                    criteria.andLessThanOrEqualTo("updateTime", value);
                } else {
                    if (field.isAnnotationPresent(CriteriaLike.class)) {
                        criteria.andLike(fieldName, "%" + value + "%");
                    } else {
                        criteria.andEqualTo(fieldName, value);
                    }
                }
            }
        }
    }

    /**
     * 根据属性名获取方法名
     *
     * @param fieldName 属性名
     * @param setMethod 是否是set方法
     * @return String
     */
    private static String methodName(String fieldName, boolean setMethod) {
        if (setMethod) {
            return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        } else {
            return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        }
    }
}
